<?php

namespace App\Api;

use App\Exceptions\InternalException;
use App\Exceptions\TokenInvalidException;
use App\Exceptions\UnCertifyException;
use Exception;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Validation\UnauthorizedException;
use Illuminate\Validation\ValidationException;
use InvalidArgumentException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
//use Tymon\JWTAuth\Exceptions\TokenBlacklistedException;
//use Tymon\JWTAuth\Exceptions\TokenInvalidException;

class ExceptionReport
{
    use ApiResponse;

    /**
     * @var Exception
     */
    public $exception;
    /**
     * @var Request
     */
    public $request;

    /**
     * @var
     */
    protected $report;

    /**
     * ExceptionReport constructor.
     * @param  Request  $request
     * @param  Exception  $exception
     */
    function __construct(Request $request, \Throwable $exception)
    {
        $this->request = $request;
        $this->exception = $exception;
    }

    /**
     * @var array
     */
    //当抛出这些异常时，可以使用我们定义的错误信息与HTTP状态码
    //可以把常见异常放在这里
    public $doReport = [
        AuthenticationException::class => ['unauthorized', 401],
        UnauthorizedHttpException::class => ['login_error', 401],
        TokenInvalidException::class => ['token_error', 401],
//        TokenBlacklistedException::class => ['token_timeout', 401],
        AuthorizationException::class => ['unauthorized', 403],
        ValidationException::class => [],
        InternalException::class => [],
        ModelNotFoundException::class => ['model_not_found', 404],
        NotFoundHttpException::class => ['page_not_found', 404],
        MethodNotAllowedHttpException::class => ['access_method_error', 405],
        QueryException::class => [],
    ];

    public function register($className, callable $callback)
    {

        $this->doReport[$className] = $callback;
    }

    /**
     * @return bool
     */
    public function shouldReturn()
    {
        foreach (array_keys($this->doReport) as $report) {
            if ($this->exception instanceof $report) {
                $this->report = $report;
                return true;
            }
        }

        return false;
    }

    /**
     * @param  Exception  $e
     * @return static
     */
    public static function make(\Throwable $e)
    {

        return new static(\request(), $e);
    }

    /**
     * @return mixed
     */
    public function report()
    {
        $message = '||异常文件：'.$this->exception->getFile().'||异常行数：'.$this->exception->getLine();
        //外部错误
        if ($this->exception instanceof TokenInvalidException) {
            $error = $this->exception->getMessage();
            return $this->unauthorized($error);
        }
        if ($this->exception instanceof ValidationException) {
            $error = Arr::collapse($this->exception->errors())[0];
            return $this->internalError($error);
        }
        //权限
        if ($this->exception instanceof UnauthorizedException) {
            $error = '该用户没有操作权限';
            return $this->unauthorized($error);
        }
        if ($this->exception instanceof NotFoundHttpException) {
            return $this->error('路由不正确', 404);
        }
        //内部错误
        if ($this->exception instanceof InvalidArgumentException) {
            $error = $this->exception->getMessage().$message;
            return $this->error($error,$this->exception->getCode());
        }
        if ($this->exception instanceof QueryException) {
            $error = $this->exception->getMessage().$message;
            return $this->error($error, 400);
        }
        if ($this->exception instanceof InternalException) {
            $error = $this->exception->getMessage().$message;
            return $this->error($error);
        }
        if ($this->exception instanceof ModelNotFoundException) {
            return $this->error('数据找不到'.$message, 404);
        }
        $default_message = $this->doReport[$this->report];
        return $this->error(trans('服务器错误'.$default_message[0]), $default_message[1].$message);
    }

    public function prodReport()
    {
        return $this->internalError('服务器错误');
    }
}
